//////////////////////////////////////////////////////////////////////
//  Jack McCaffery
//  11-10-2014
//////////////////////////////////////////////////////////////////////

#include "topicModel/basicData.H"
#include "typedefs.H"

using namespace Eigen;

#include <fstream>
#include <sstream>
#include <cstdio>
using namespace std;


template <class SC>
ScriptHelper<SC>::ScriptHelper (BasicData<SC> &container_, int i_) :
	index (i_),
	container (container_)
{

}

template <class SC>
SC &ScriptHelper<SC>::operator[] (int j_)
{
	return container.getData () (index, j_);
}


///////////////////////////////////////////////////////////////////////////

template <class SC>
ConstScriptHelper<SC>::ConstScriptHelper (BasicData<SC> const &container_,
					  int i_) :
	index (i_),
	container (container_)
{

}

template <class SC>
SC ConstScriptHelper<SC>::operator[] (int j_) const
{
	return container.getData () (index, j_);
}


///////////////////////////////////////////////////////////////////////////

template <class SC>
BasicData<SC>::~BasicData ()
{

}

template <class SC>
BasicData<SC>::BasicData () :
	data ()
{

}

template <class SC>
bool BasicData<SC>::load (QString const filename_)
{
	FILE *ifile;

	int rows = 0;
	int cols = 0;

	unsigned scalarSize = 0;

	char const *fname = filename_.toStdString ().c_str ();

	ifile = fopen (fname, "r");

	unsigned nRead = 0;

	nRead = fscanf (ifile, "%d, %d, %d\n", &rows, &cols, &scalarSize);

	if (nRead != 3)
		return false;

	if (scalarSize != sizeof (SC))
		return false;

	data.resize (rows, cols);

	nRead = fread (data.data (), sizeof (SC), rows * cols, ifile);

	if (nRead != sizeof (SC) * rows * cols)
		return false;

	if (! _load (ifile))
		return false;

	return true;
}

template <class SC>
bool BasicData<SC>::save (QString const filename_) const
{
	FILE *ofile;

	stringstream header;

	char const *fname = filename_.toStdString ().c_str ();

	ofile = fopen (fname, "w");

	if (ofile == 0)
		return false;

	header << data.rows () << ", " << data.cols ()  << ", "
	       << sizeof (SC) << '\n';

	fwrite (header.str ().c_str (), 1, header.str ().size (), ofile);

	unsigned imageSize = data.rows () * data.cols ();

	fwrite (data.data (), sizeof (SC), imageSize, ofile); 

	if (! _save (ofile))
		return false;

	fclose (ofile);

	return true;
}

template <class SC>
Matrix<SC, Dynamic, Dynamic> const &BasicData<SC>::getData () const
{
	return data;
}

template <class SC>
Matrix<SC, Dynamic, Dynamic> &BasicData<SC>::getData ()
{
	return data;
}

template <class SC>
bool BasicData<SC>::operator== (BasicData<SC> const &other_) const
{
	return data == other_.getData();
}
/*
template <>
bool BasicData<float>::operator== (BasicData<float> const &other_) const
{
	return data.isApprox (other_.getData ());
}

template <>
bool BasicData<double>::operator== (BasicData<double> const &other_) const
{
	return data.isApprox (other_.getData ());
}
*/
template <class SC>
bool BasicData<SC>::operator!= (BasicData<SC> const &other_) const
{
	return ! (*this == other_);
}

template <class SC>
ScriptHelper<SC> BasicData<SC>::operator[] (int i_)
{
	return ScriptHelper<SC> (*this, i_);
}

template <class SC>
ConstScriptHelper<SC> BasicData<SC>::operator[] (int i_) const
{
	return ConstScriptHelper<SC> (*this, i_);
}

template class BasicData<bool>;
template class BasicData<short>;
template class BasicData<unsigned short>;
template class BasicData<int>;
template class BasicData<unsigned int>;
template class BasicData<float>;
template class BasicData<double>;

template class ScriptHelper<bool>;
template class ScriptHelper<short>;
template class ScriptHelper<unsigned short>;
template class ScriptHelper<int>;
template class ScriptHelper<unsigned int>;
template class ScriptHelper<float>;
template class ScriptHelper<double>;

template class ConstScriptHelper<bool>;
template class ConstScriptHelper<short>;
template class ConstScriptHelper<unsigned short>;
template class ConstScriptHelper<int>;
template class ConstScriptHelper<unsigned int>;
template class ConstScriptHelper<float>;
template class ConstScriptHelper<double>;
